package idv.takeshi.software.productline.bookstore.domain.model.book;

import java.math.BigDecimal;

import javax.persistence.Column;
import javax.persistence.Embeddable;
import javax.persistence.Entity;

import org.apache.commons.lang.Validate;
import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;

/**
 * A model class which is one kind of promotion, price-off.
 * @author takeshi
 *
 */
@Entity
public class PriceOff extends Promotion {
	@Column(name = "PRICE_OFF")
	private BigDecimal priceOff = new BigDecimal("0");

	/**
	 * @return the priceOff
	 */
	public BigDecimal getPriceOff() {
		return priceOff;
	}

	/**
	 * Set priceOff.
	 * Here are two check rules before setting the priceOff<br>
	 * <ol>
	 * 	<li>priceOff shall not small than 0</li>
	 * 	<li>priceOff shall not greater than book.fixedPrice</li>
	 * </ol>
	 * @param priceOff the priceOff to set
	 * @throws PriceOffSettingException if above check rules violated. 
	 */
	public void setPriceOff(BigDecimal priceOff, Book book) throws PriceOffSettingException {
		Validate.notNull(priceOff, "priceOff shall always not be null");
		BigDecimal fixedPrice = getFixedPrice(book);
		if(priceOff.compareTo(new BigDecimal("0")) < 0){
			throw new PriceOffSmallThanZeroException("priceOff:" + priceOff + 
					" shall not small than 0");
		}
		if(priceOff.compareTo(fixedPrice) > 0){
			throw new PriceOffGreaterThanFixedPriceException("priceOff:" + priceOff + 
				" shall not greater than book.fixedPrice:" + fixedPrice);
		}
		this.priceOff = priceOff;
	}

	/**
	 * Calculate a promoted price by priceOff algorithm.
	 * @param book
	 * @return calculated price
	 */
	@Override
	public BigDecimal getPromotedPrice(Book book) {
		BigDecimal fixedPrice = getFixedPrice(book);
		return fixedPrice.subtract(priceOff);
	}
	
	/* (non-Javadoc)
	 * @see idv.takeshi.software.productline.bookstore.domain.model.book.Promotion#equals(java.lang.Object)
	 */
	@Override
	public boolean equals(Object obj) {
		if (obj == null) { return false; }
		   if (obj == this) { return true; }
		   if (obj.getClass() != getClass()) {
		     return false;
		   }
		   PriceOff rhs = (PriceOff) obj;
		   return new EqualsBuilder()
		   	   .appendSuper(super.equals(rhs))
			   .append(this.priceOff, rhs.priceOff)
		       .isEquals();
	}

	/* (non-Javadoc)
	 * @see idv.takeshi.software.productline.bookstore.domain.model.book.Promotion#hashCode()
	 */
	@Override
	public int hashCode() {
		return new HashCodeBuilder(13, 17).
		   appendSuper(super.hashCode()).
	       append(this.priceOff).
	       toHashCode();
	}
	
}
 
